#include <stdio.h>

struct packet {
    uint32_t packet_num;
	uint32_t crc;
	uint16_t cmd;
	uint16_t len;
	uint8_t* payload;
};

uint8_t pkt_rx_buff[256];
uint8_t pkt_tx_buff[256];

uint32_t crc32_compute(uint8_t *p, uint32_t len)
{
    uint32_t i,j;
    uint32_t crc = 0xffffffff;
    for(j=0;j<len;j++)
    {
        crc = crc ^ *p++;
        for (i = 0;i<8;i++)
        {
            crc = (crc >> 1) ^ (0xedb88320 &  -(crc & 1));
        }
    }
    return ~crc;
}

int parser_packet(uint8_t* buff, uint32_t len, struct packet* pkt)
{
    if (len < 12 || len > sizeof(pkt_rx_buff)) {
		return -1;
    }
    pkt->packet_num = *((uint32_t*)buff);
	pkt->crc = *((uint32_t*)(buff + 4));
	pkt->cmd = *((uint16_t*)(buff + 8));
	pkt->len = *((uint16_t*)(buff + 10));
	pkt->payload = buff + 12;

	if (len < 12 + pkt->len ) {
		return -2;
    }

	*((uint32_t*)(buff + 4)) = 0;
	uint32_t crc32 = crc32_compute(buff, 12 + pkt->len);
	if (crc32 == pkt->crc) {
		return 0;
    }
    return -3;
}

int prepare_packet(uint8_t* buff, uint32_t len, struct packet* pkt)
{
    if (pkt->len + 12 > len || pkt->len + 12 > sizeof(pkt_tx_buff)) {
		while(1);
		return -1;
    }
    *((uint32_t*)buff) = pkt->packet_num;
	*((uint32_t*)(buff + 4)) = 0;
	*((uint16_t*)(buff + 8)) = pkt->cmd;
	*((uint16_t*)(buff + 10)) = pkt->len;
	memcpy(buff + 12, pkt->payload, pkt->len);
	uint32_t crc32 = crc32_compute(buff, 12 + pkt->len);
	*((uint32_t*)(buff + 4)) = crc32;
	return 0;
}

#define CMD_CONNECT 0x1
#define CMD_REBOOT 0x2
#define CMD_WRITE_FLASH 0x3
#define CMD_GET_CRC 0x4



int process_packet(struct packet* pkt)
{
    int ret;
    struct packet tx_pkt;
	tx_pkt->cmd = pkt->cmd;
	switch(pkt->cmd) {
		case CMD_CONNECT:
			break;
		case CMD_REBOOT:
			break;
		case CMD_WRITE_FLASH:
			break;
		case CMD_GET_CRC:
			break;
    }
	tx_pkt->packet_num = pkt->packet_num;
	tx_pkt->
}

volatile uint32_t g_i2c_recv_len = 0;
volatile uint8_t g_i2c_recv_packet_ready = 0;

void process()
{
    struct packet rx_pkt;
    if (!g_i2c_recv_packet_ready) {
		return;
    }
	memcpy(pkt_rx_buff, g_i2c_rx_buff, g_i2c_recv_len);
	memset(&rx_pkt, 0, sizeof(rx_pkt));
    int ret = parser_packet(g_i2c_rx_buff, g_i2c_recv_len, &rx_pkt);
    if (ret != 0) {
		g_i2c_recv_packet_ready = 0;
		return;
    }
	process_packet(&rx_pkt, );
	memset();
	g_i2c_recv_packet_ready = 0;
	return;
}
